package com.zytech.zspider.core;

import com.google.common.collect.Maps;
import com.zytech.modules.lang.Requires;
import com.zytech.modules.lang.Strings;
import com.zytech.modules.lang.annotations.Immutable;

import java.io.Serializable;
import java.util.Collections;
import java.util.Map;

/**
 * spider definition for a website.
 * diff with TaskDefinition, it is immutable, but TaskDefinition is mutable.
 *
 * @author siuming
 */
@Immutable
public class SpiderDefinition implements Serializable {

    private static final long serialVersionUID = 3647025525058875864L;

    private final String id;
    private final String name;
    private final String bodyGenerator;
    private final Map<String, String> headers;// headers using for spiderTask.
    private final Map<String, String> params;// params using for spiderTask.
    private final Map<String, String> paramsGenerator;// scripts for create params.
    private final Map<String, String> settings;// predifined settings.

    private final TaskDefinition taskDefinition;

    /**
     * @param builder
     */
    SpiderDefinition(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.bodyGenerator = builder.bodyGenerator;
        this.headers = builder.headers;
        this.params = builder.params;
        this.paramsGenerator = builder.paramsGenerator;
        this.settings = builder.settings;
        this.taskDefinition = builder.taskDefinition;
    }

    /**
     * @return
     */
    public String getId() {
        return id;
    }

    /**
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     * @return
     */
    public String getBodyGenerator() {
        return bodyGenerator;
    }

    /**
     * @return
     */
    public boolean isEmptyBodyGenerator() {
        return Strings.isBlank(bodyGenerator);
    }

    /**
     * @return
     */
    public Map<String, String> getHeaders() {
        return Collections.unmodifiableMap(headers);
    }

    /**
     * @return
     */
    public Map<String, String> getParams() {
        return Collections.unmodifiableMap(params);
    }

    /**
     * @return
     */
    public boolean isEmptyParams() {
        return params.isEmpty();
    }

    /**
     * @return
     */
    public Map<String, String> getParamsGenerator() {
        return Collections.unmodifiableMap(paramsGenerator);
    }

    /**
     * @return
     */
    public boolean isEmptyParamsGenerator() {
        return paramsGenerator.isEmpty();
    }

    /**
     * @return
     */
    public Map<String, String> getSettings() {
        return Collections.unmodifiableMap(settings);
    }

    /**
     * @return
     */
    public TaskDefinition getTaskDefinition() {
        return taskDefinition;
    }

    /**
     * @return
     */
    public static Builder ofBuilder() {
        return new Builder();
    }

    public static class Builder {

        String id;
        String name;
        String bodyGenerator;
        Map<String, String> headers = Maps.newHashMap();
        Map<String, String> params = Maps.newHashMap();
        Map<String, String> paramsGenerator = Maps.newHashMap();
        Map<String, String> settings = Maps.newHashMap();
        TaskDefinition taskDefinition;

        Builder() {
        }

        /**
         * @param id
         * @return
         */
        public Builder id(String id) {
            Requires.hasText(id, "id must not be null or empty.");
            this.id = id;
            return this;
        }

        /**
         * @param name
         * @return
         */
        public Builder name(String name) {
            Requires.hasText(name, "name must not be null or empty.");
            this.name = name;
            return this;
        }

        /**
         * @param bodyGenerator
         * @return
         */
        public Builder bodyGenerator(String bodyGenerator) {
            Requires.hasText(bodyGenerator, "bodyGenerator must not be null or empty.");
            this.bodyGenerator = bodyGenerator;
            return this;
        }

        /**
         * @param headers
         * @return
         */
        public Builder headers(Map<String, String> headers) {
            Requires.notNull(headers, "headers must not be null.");
            this.headers = headers;
            return this;
        }

        /**
         * @param headers
         * @return
         */
        public Builder params(Map<String, String> params) {
            Requires.notNull(params, "params must not be null.");
            this.params = params;
            return this;
        }

        /**
         * @param paramGenerator
         * @return
         */
        public Builder paramsGenerator(Map<String, String> paramGenerator) {
            Requires.notNull(paramGenerator, "paramsGenerator must not be null.");
            this.paramsGenerator = paramGenerator;
            return this;
        }

        /**
         * @param settings
         * @return
         */
        public Builder settings(Map<String, String> settings) {
            Requires.notNull(settings, "settings must not be null.");
            this.settings = settings;
            return this;
        }

        /**
         * @param task
         * @return
         */
        public Builder task(TaskDefinition task) {
            Requires.notNull(task, "task must not be null.");
            this.taskDefinition = task;
            return this;
        }

        /**
         * @return
         */
        public SpiderDefinition build() {
            return new SpiderDefinition(this);
        }
    }
}
